<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>drawRectangle(未接入lve.js)</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    .container{
      width: 1000px;
      height: 600px;
      margin: 10% auto;
    }
    .control{
      margin-bottom: 10px;
      display: flex;
    }
    .control > button {
      margin-right: 10px;
    }
    #out-box{
      width: 100%;
      height: 550px;
      border: 2px solid #000;
      position: relative;
      overflow: hidden;
    }
    .rect{
      position: absolute;
      box-shadow: 0 0 0 1999px rgba(0, 0, 0, .4);
      left: -9999px;
      top: 0;
      width: 0;
      height: 0;
      border: 2px solid orange;
      cursor: move;
    }
    .rect>span{
      position: absolute;
      width: 6px;
      height: 6px;
      border-radius: 50%;
      border: 2px solid orange;
      background-color: #fff;
    }
    .rect .left-top{
      left: -6px;
      top: -6px;
      cursor: nwse-resize;
    }
    .rect .middle-top{
      left: 50%;
      top: -6px;
      transform: translateX(-50%);
      cursor: n-resize;
    }
    .rect .right-top{
      right: -6px;
      top: -6px;
      cursor: nesw-resize;
    }
    .rect .right-middle{
      right: -6px;
      top: 50%;
      transform: translateY(-50%);
      cursor: e-resize;
    }
    .rect .right-bottom{
      right: -6px;
      bottom: -6px;
      cursor: nwse-resize;
    }
    .rect .middle-bottom{
      left: 50%;
      bottom: -6px;
      transform: translateX(-50%);
      cursor: s-resize;
    }
    .rect .left-bottom{
      left: -6px;
      bottom: -6px;
      cursor: nesw-resize;
    }
    .rect .left-middle{
      left: -6px;
      top: 50%;
      transform: translateY(-50%);
      cursor: w-resize;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="control">
      <button id="clear">清屏</button>
      <button id="start-paint">开始绘制</button>
      <div>
        <input type="radio" id="color-1" name="color-choose" value="orange">
        <label for="color-1">黄框</label>
        <input type="radio" id="color-2" name="color-choose" value="#02A7F0">
        <label for="color-2">蓝框</label>
      </div>
    </div>
    <div id="out-box">
      <div id="rect" class="rect">
        <span class="left-top dot"></span>
        <span class="middle-top dot"></span>
        <span class="right-top dot"></span>
        <span class="right-middle dot"></span>
        <span class="right-bottom dot"></span>
        <span class="middle-bottom dot"></span>
        <span class="left-bottom dot"></span>
        <span class="left-middle dot"></span>
      </div>
    </div>
  </div>
  
  <script>
    const dom = document.getElementById('out-box')
    const rect  = document.getElementById('rect')
    const origin = dom.getBoundingClientRect()
    const parentBorder = Number(getComputedStyle(dom, null).borderWidth.split('px')[0]) // 父元素边框 如果你明确知道边框宽度，就不需要这行，直接赋值就行
    const childBorder = Number(getComputedStyle(rect, null).borderWidth.split('px')[0]) // 子元素边框 如果你明确知道边框宽度，就不需要这行，直接赋值就行
    /**
     * 开始绘制
     */
    const startMouse = () => {
      dom.style.cursor = 'crosshair'
      dom.onmousedown = e => {
        if (e.target !== dom) return
        const left = e.offsetX
        const top = e.offsetY
        rect.style.left = left + 'px'
        rect.style.top = top + 'px'
        rect.style.borderColor = getCurrentColor() // 绘制时使用选择的框的颜色
        const childs = rect.children
        for (let i = 0; i < childs.length; i++) {
          childs[i].style.borderColor = getCurrentColor() // 绘制时使用选择的框的颜色
        }
        dom.onmousemove = e => {
          // 宽高边界限制
          const widthArea = e.clientX - origin.x > dom.offsetWidth - (parentBorder * 2 + childBorder * 2) ? dom.offsetWidth - (parentBorder * 2 + childBorder * 2) : e.clientX - origin.x
          const heightArea = e.clientY - origin.y > dom.offsetHeight - (parentBorder * 2 + childBorder * 2) ? dom.offsetHeight - (parentBorder * 2 + childBorder * 2) : e.clientY - origin.y
          rect.style.width = widthArea - left + 'px'
          rect.style.height = heightArea - top + 'px'
        }
        dom.onmouseup = e => {
          dom.onmousedown = null
          dom.onmousemove = null
          dom.onmouseup = null
          dom.style.cursor = ''
          editMouse()
        }
      }
    }
    const editMouse = () => {
      rect.onmousedown = e => {
        if (e.target !== rect && e.target.className.indexOf('dot') === -1) return // 类名中包含被放行的dot除外
        const flag = mousedownHandle(e)
        let left = e.clientX
        let top = e.clientY
        const width = rect.offsetWidth
        const height = rect.offsetHeight
        const [dragX, dragY] = flag
        // 拖动
        if (dragX === -1 && dragY === -1) {
          left -= rect.offsetLeft // 要保持之前矩形框的坐标值
          top -= rect.offsetTop
        }
        const child = e.target.getBoundingClientRect()
        document.onmousemove = e => {
          // 取消浏览器因回流导致的默认事件及冒泡事件
          e.preventDefault()
          if (e.stopPropagation) {
            e.stopPropagation()
          } else {
            e.cancelable = true
          }
          const finallPoint = {
            left: 0,
            top: 0,
            width: 0,
            height: 0
          }
          if (dragX === -1 && dragY === -1) {
            rect.style.cursor = 'move'
            const rightArea = dom.offsetWidth - rect.offsetWidth - (childBorder * 2) // 右边界
            const bottomArea = dom.offsetHeight - rect.offsetHeight - (childBorder * 2) // 下边界
            const leftArea = 0 // 左边界
            const topArea = 0 // 上边界
            finallPoint.left = e.clientX - left > rightArea ? rightArea : (e.clientX - left< leftArea ? leftArea : e.clientX - left)
            finallPoint.top = e.clientY - top > bottomArea ? bottomArea : (e.clientY - top < topArea ? topArea : e.clientY - top)
            rect.style.left = finallPoint.left + 'px'
            rect.style.top = finallPoint.top + 'px'
          } else if (dragX === 0 && dragY === 0) { // 左上角拉伸
            finallPoint.left = e.clientX > origin.x ? ((e.clientX > (left + width)) ? left + width - origin.x : e.clientX - origin.x) : 0
            finallPoint.top = e.clientY > origin.y ? ((e.clientY > (top + height)) ? top + height - origin.y : e.clientY - origin.y) : 0
            finallPoint.width = e.clientX > origin.x ? ((e.clientX > (left + width)) ? 0 : width + (left - e.clientX)) : width + (left - origin.x)
            finallPoint.height = e.clientY > origin.y ? ((e.clientY > (top + height)) ? 0 : height + (top - e.clientY)) : height + (top - origin.y)
            rect.style.left = finallPoint.left + 'px'
            rect.style.top = finallPoint.top + 'px'
            rect.style.width = finallPoint.width + 'px'
            rect.style.height = finallPoint.height + 'px'
          } else if (dragX === 1 && dragY === 0) { // 中上拉伸
            finallPoint.top = e.clientY > origin.y ? ((e.clientY > (top + height)) ? top + height - origin.y : e.clientY - origin.y) : 0
            finallPoint.height = e.clientY > origin.y ? ((e.clientY > (top + height)) ? 0 : height + (top - e.clientY)) : height + (top - origin.y)
            rect.style.top = finallPoint.top + 'px'
            rect.style.height = finallPoint.height + 'px'
          } else if (dragX === 2 && dragY === 0) { // 右上角拉伸
            finallPoint.top = e.clientY > origin.y ? ((e.clientY > (top + height)) ? top + height - origin.y : e.clientY - origin.y) : 0
            finallPoint.width = (e.clientX - left + width > dom.offsetWidth - rect.offsetLeft - (parentBorder * 2 + childBorder * 2) ? dom.offsetWidth - rect.offsetLeft - (parentBorder * 2 + childBorder * 2) : e.clientX - left + width)
            finallPoint.height = e.clientY > origin.y ? ((e.clientY > (top + height)) ? 0 : height + (top - e.clientY)) : height + (top - origin.y)
            rect.style.top = finallPoint.top + 'px'
            rect.style.width = finallPoint.width + 'px'
            rect.style.height = finallPoint.height + 'px'
          } else if (dragX === 2 && dragY === 1) { // 右中拉伸
            finallPoint.width = (e.clientX - left + width > dom.offsetWidth - rect.offsetLeft - (parentBorder * 2 + childBorder * 2) ? dom.offsetWidth - rect.offsetLeft - (parentBorder * 2 + childBorder * 2) : e.clientX - left + width)
            rect.style.width = finallPoint.width + 'px'
          }else if (dragX === 2 && dragY === 2) { // 右下角拉伸
            finallPoint.width = (e.clientX - left + width > dom.offsetWidth - rect.offsetLeft - (parentBorder * 2 + childBorder * 2) ? dom.offsetWidth - rect.offsetLeft - (parentBorder * 2 + childBorder * 2) : e.clientX - left + width)
            finallPoint.height = (e.clientY- top + height > dom.offsetHeight - rect.offsetTop - (parentBorder * 2 + childBorder * 2) ? dom.offsetHeight - rect.offsetTop - (parentBorder * 2 + childBorder * 2) : e.clientY- top + height)
            rect.style.width = finallPoint.width + 'px'
            rect.style.height = finallPoint.height + 'px'
          } else if (dragX === 1 && dragY === 2) { // 中下拉伸
            finallPoint.height = (e.clientY- top + height > dom.offsetHeight - rect.offsetTop - (parentBorder * 2 + childBorder * 2) ? dom.offsetHeight - rect.offsetTop - (parentBorder * 2 + childBorder * 2) : e.clientY- top + height)
            rect.style.height = finallPoint.height + 'px'
          } else if (dragX === 0 && dragY === 2) { // 左下角拉伸
            finallPoint.left = e.clientX > origin.x ? ((e.clientX > (left + width)) ? left + width - origin.x : e.clientX - origin.x) : 0
            finallPoint.width = e.clientX > origin.x ? ((e.clientX > (left + width)) ? 0 : width + (left - e.clientX)) : width + (left - origin.x)
            finallPoint.height = (e.clientY- top + height > dom.offsetHeight - rect.offsetTop - (parentBorder * 2 + childBorder * 2) ? dom.offsetHeight - rect.offsetTop - (parentBorder * 2 + childBorder * 2) : e.clientY- top + height)
            rect.style.left = finallPoint.left + 'px'
            rect.style.width = finallPoint.width + 'px'
            rect.style.height = finallPoint.height + 'px'
          } else if (dragX === 0 && dragY === 1) { // 左中拉伸
            finallPoint.left = e.clientX > origin.x ? ((e.clientX > (left + width)) ? left + width - origin.x : e.clientX - origin.x) : 0
            finallPoint.width = e.clientX > origin.x ? ((e.clientX > (left + width)) ? 0 : width + (left - e.clientX)) : width + (left - origin.x)
            rect.style.left = finallPoint.left + 'px'
            rect.style.width = finallPoint.width + 'px'
          }
        }
        document.onmouseup = e => {
          document.onmousemove = null
          document.onmouseup = null
          rect.style.cursor = 'move'
        }
      }
    }
    /**
     * mousedown逻辑处理
     */
    const mousedownHandle = (e) => {
      let flag = 0 // 点击的是除边角以外的其他部分 拖动
      let startX = e.offsetX
      let startY = e.offsetY
      let width = e.target.offsetWidth
      let height = e.target.offsetHeight
      if (e.target !== rect) {
        flag = 1 // 点击的是边角 缩放
        const parent = e.target.offsetParent.getBoundingClientRect()
        const child = e.target.getBoundingClientRect()
        startX = child.x - parent.x
        startY = child.y - parent.y
        width = e.target.offsetParent.offsetWidth
        height = e.target.offsetParent.offsetHeight
      }
      const difference = 12 // 点击四边角12 px范围为拉伸，其他为拖动,这个值可以根据你需要的来调整
      let left = 0 // 0 => left, 1 => middle, 2 => right, -1 => 点击的位置不能被拖动
      let top = 0 // 0 => top, 1 => middle, 2 => bottom, -1 => 点击的位置不能被拖动
      if (startX < difference) { // 点击的位置为矩形左侧
        left = 0
      } else if (startX > width / 2 - difference && startX < width / 2 + difference) { // 点击的位置为矩形中间 width/2 - 6px ~ width/2 + 6px
        left = 1
      } else if (startX < width && startX > width - difference){ // 点击的位置为矩形右侧 width - 6px ~ width
        left = 2
      } else {
        left = -1
      }

      if (startY < difference) { // 点击的位置为矩形上侧
        top = 0
      } else if (startY > height / 2 - difference && startY < height / 2 + difference) { // 点击的位置为矩形中间 height/2 - 6px ~ height/2 + 6px
        top = 1
      } else if (startY < height && startY > height - difference){ // 点击的位置为矩形下侧 height - 6px ~ height
        top = 2
      } else {
        top = -1
      }
      if (left === -1 || top === -1 || (left === 1 && top === 1)) {
        return [-1, -1]
      }
      return [left, top] // 只会有八个位置能被准确返回，其余都是返回[-1, -1]
    }

    const clear = document.querySelector('#clear') // 清屏
    const startPaint = document.querySelector('#start-paint') // 开始绘制
    const radioList = document.getElementsByName('color-choose')
    radioList[0].checked = "checked"
    
    const getCurrentColor = () => {
      for (let i = 0; i < radioList.length; i++) {
        if (radioList[i].checked) {
          return radioList[i].value
        }
      }
    }
    
    clear.onclick = e => {
      rect.style.left = '-9999px'
      rect.style.top = 0
      rect.style.width = 0
      rect.style.height = 0
    }
    startPaint.onclick = e => {
      startMouse()
    }
  </script>
</body>
</html>